
// For debug output to console
CanvasObject.debug = true;

function CanvasObject(tagType) {
	this.dprint("CanvasObjectV2 constructor: type->" + tagType);
	

	this.idName = "object";
	this.idNum = (CanvasObject.nextId++);
	this.id = this.idName + this.idNum;
	
	this.parent = null;
	this.isSelected = false;
	this.selectedObject = null;
	
	this.children = new Array();
	
	if (tagType != undefined) {
		this.tagType = tagType;
	} else {
		this.tagType = "div";
	}
	this.tagProperties = ""
	
	this.isVisible = true;
	
	this.content = "";
	this.classes = [];
	
	//this.customCss = [];
	this.attributes = {
		"x": { cssName: "left", value: 100, setter: "setX" },
		"y": { cssName: "top", value: 100, setter: "setY" },
		"width": { cssName: "width", value: 100, setter: "setWidth"},
		"height": { cssName: "height", value: 100, setter: "setHeight"},
		//"opacity": { cssName: "opacity", value: "0.8"},
		"background": { cssName: "background", value: "#d0d0d0"},
		"backgroundImage": { cssName: "background-image", value: "", setter: "setBackgroundImage"},
		"z-index": { cssName: "z-index", value: "1"}
	};
	
	
	
	this.initDomElem();
	
	// Set up default attributes
	for( var name in this.attributes ) {
		var attr = this.attributes[name];
		//this.dprint("attr: " + attr.name + " value: " + attr.value);
		if (attr.value != undefined) {
			this.setAttribute(name, attr.value);
		}
	}
}


CanvasObject.className = "CanvasObject";
CanvasObject.nextId = 0;

CanvasObject.attributes = [
	{name: "id"},
	{name: "x", cssName: "left", value: 100 },
	{name: "y", cssName: "top", value: 100},
	{name: "width", cssName: "width", value: 100},
	{name: "height", cssName: "height", value: 100},
	//{name: "opacity", cssName: "opacity", value: "0.8"},
	{name: "background", cssName: "background", value: "#d0d0d0"},
	{name: "backgroundImage", cssName: "background-image", value: ""},
	{name: "z-index", cssName: "z-index", value: "1"}
];

CanvasObject.prototype.initDomElem = function() {
	// Create DOM element
	//this.container = $("#canvas");
	this.domElem = $("<"+"div"+" id='"+this.id+"' class='object ui-widget-content'></div>");

	// TODO: fix this to use the parent, not the global canvas
	// theCanvas().domElem.append(this.domElem);
	
	// Set up click handlers
	var obj = this;

	if (this.parent != null) {

	}
	
};

CanvasObject.prototype.toJSON = function(key) {

	this.dprint("toJSON!");

	var j_children = [];
	for (var i in this.children) {
		j_children.push(this.children[i].toJSON());
	}
	
	var j_classes = [];
	for (var i in this.classes) {
		j_classes.push(this.classes[i].toJSON());
	}
	
	var j_attributes = [];
	for (var i in this.attributes) {
		j_attributes.push({ name: i, value: this.attributes[i].value });
	}

	return {
		id: this.idName,
		tagType: this.tagType,
		tagProperties: this.tagProperties,
		children: j_children,
		classes: j_classes,
		//customCss: j_customCss,
		attributes: j_attributes,
		content: this.content
	};

};

CanvasObject.buildFromJSON = function(jsonObj) {
	//var obj = JSON.parse(jsonStr);
	var obj = jsonObj;
	
	var root = new CanvasObject(obj.tagType);
	root.tagProperties = (obj.tagProperties != undefined ? obj.tagProperties : "");
	
	root.setId(obj.id);
	root.setContent(obj.content);

	
	for(var c in obj.classes) {
		root.addClass(obj.classes[c]);
	}
	
	for (var i in obj.attributes) {
		var attr = obj.attributes[i];
		root.setAttribute(attr.name, attr.value);
	}
	
	for (var i in obj.children) {
		var c = obj.children[i];
		//alert(c);
		
		var childObj = CanvasObject.buildFromJSON(c);
		root.addObject( childObj );
		childObj.disableClickHandlers();
	}
	
	//root.setIsSelected(false);
	
	return root;
	
};

CanvasObject.prototype.setParent = function(p) {
	this.parent = p;
	//this.setupClickHandlers();
	this.enableClickHandlers();
};

CanvasObject.prototype.getParent = function() {
	return this.parent;
};	

CanvasObject.prototype.setupClickHandlers = function() {
	
	if (this.parent != null) {
	
		var obj = this;
	
		this.domElem.draggable({ 
			containment: this.parent.domElem, 
			start: function(event, ui) {
				obj.dprint("start draggin");
				obj.parent.setSelectedObject(this);
				//_objects[this.id].setIsSelected(true);
			},
			drag : function(event, ui) {
				obj.setAttribute("x", obj.domElem.position().left);
				obj.setAttribute("y", obj.domElem.position().top);
			
				//obj.setX(obj.domElem.position().left);
				//obj.setY(obj.domElem.position().top);
			},
			stop: function(event, ui) {
				obj.setAttribute("x", obj.domElem.position().left);
				obj.setAttribute("y", obj.domElem.position().top);
		
				//obj.setX(obj.domElem.position().left);
				//obj.setY(obj.domElem.position().top);
				obj.dprint("done draggin");
			}
		});
		
		this.domElem.resizable({ 
			handles: 'se, sw, ne, nw',
			containment: this.parent.domElem,
			resize: function(event, ui) {
				obj.setAttribute("width", obj.domElem.width());
				obj.setAttribute("height", obj.domElem.height());
				//obj.setAttribute("x", obj.domElem.position().left);
				//obj.setAttribute("y", obj.domElem.position().top);
				
				//obj.setWidth(obj.domElem.width());
				//obj.setHeight(obj.domElem.height());
			},
			stop: function(event, ui) {
				obj.setAttribute("x", obj.domElem.offset().left);
				obj.setAttribute("y", obj.domElem.offset().top);
			}
			
		});
			
		this.domElem.click(function(e) {
		
			obj.dprint("click!");
			
			if (obj == obj.parent.shapeBeingMade) {
				obj.parent.endCreatingShape();
			} else {			
				obj.parent.setSelectedObject(this);
				//_objects[this.id].setIsSelected(true);
		
				e.stopPropagation();
				//this.setIsSelected(!this.selected);
			}
		});
		
	
		
		this.domElem.mouseenter(function(e) { $(this).toggleClass("hover", true); });
		this.domElem.mouseleave(function(e) { $(this).toggleClass("hover", false); });
	}
};

CanvasObject.prototype.enableClickHandlers = function() {
	
	if (this.parent != null) {
		var obj = this;
	
		this.domElem.draggable({ 
			containment: this.parent.domElem, 
			start: function(event, ui) {
				obj.dprint("start draggin");
				obj.parent.setSelectedObject(this);
				//_objects[this.id].setIsSelected(true);
			},
			drag : function(event, ui) {
				obj.setAttribute("x", obj.domElem.position().left);
				obj.setAttribute("y", obj.domElem.position().top);
			
				//obj.setX(obj.domElem.position().left);
				//obj.setY(obj.domElem.position().top);
			},
			stop: function(event, ui) {
				obj.setAttribute("x", obj.domElem.position().left);
				obj.setAttribute("y", obj.domElem.position().top);
		
				//obj.setX(obj.domElem.position().left);
				//obj.setY(obj.domElem.position().top);
				obj.dprint("done draggin");
			}
		});
		
		this.domElem.resizable({ 
			handles: 'se, sw, ne, nw',
			containment: this.parent.domElem,
			resize: function(event, ui) {
				obj.setAttribute("width", obj.domElem.width());
				obj.setAttribute("height", obj.domElem.height());
				obj.setAttribute("x", obj.domElem.position().left);
				obj.setAttribute("y", obj.domElem.position().top);		
			},
			stop: function(event, ui) {
				obj.setAttribute("x", obj.domElem.position().left);
				obj.setAttribute("y", obj.domElem.position().top);
			}
			
		});
		
		this.domElem.click(function(e) {		
			obj.dprint("click!");
			if (!obj.isVisible) {
				return;
			}
			
			
			if (obj == obj.parent.shapeBeingMade) {
				obj.parent.endCreatingShape();
			} else {			
				obj.parent.setSelectedObject(this);
				//_objects[this.id].setIsSelected(true);
		
				e.stopPropagation();
				//this.setIsSelected(!this.selected);
			}
		});
	}
};

CanvasObject.prototype.disableClickHandlers = function() {
	this.domElem.draggable('destroy');
	this.domElem.resizable('destroy');
	this.domElem.unbind('click');
	this.domElem.removeClass("selected");
};


CanvasObject.prototype.addObject = function(o) {
	this.dprint("addObject: " + o.id);
	
	this.children[o.id] = o;
	o.setParent(this);
	this.domElem.append(o.domElem);
	
	//this.dprint("child: " + this.children[o.id]);
	this.dprint("num children: " + this.children.length);
};

// Is o a domElem? or an object?
CanvasObject.prototype.removeObject = function(o) {
	this.dprint("removeObject: " + o.id);
	
	o.domElem.remove();
	o.setParent(null);
	delete this.children[o.id]; // remove from array of objects
	//o.remove();
	
	o.destroy();
};

CanvasObject.prototype.setAttribute = function(name, val) {
	this.dprint("set val: " + name + "->" + val);
	
	var attr = this.attributes[name];
	if (attr == undefined) {
	
		this.dprint("attribute undefined");
	
		attr = { cssName: name, value: val };
		this.attributes[name] = attr;
		this.setCss(name, val);
		
	} else {
	
		// Set value to default before calling setter, so setter
		// can set to custom format if it needs to
		// Ex. background-image wraps image url in "url('imgurl')"
		attr.value = val;
	
		// Custom setter is defined, so use it
		if (attr.setter != undefined) {
			this.dprint("attr has a setter");
			this[attr.setter](val);
			
		// Otherwise, set css directly
		} else {
			this.dprint("no setter for attr");
		
			// Make sure to use proper css name
			if (attr.cssName == undefined) {
				this.setCss(name, val);
			} else {
				this.setCss(attr.cssName, val)
			}
			
			
		}
	}
	
	if (theCanvas() != null && theCanvas().baseObject == this) {
		theControlPanel().canvasAttributeChanged(name, val);
	} else {
		theControlPanel().objectAttributeChanged(name, val);
	}
};

CanvasObject.prototype.getAttribute = function(name) {

	var attr = this.attributes[name];
	if (attr == undefined) { return ""; }
	else if (attr.cssName == undefined) {
		
	}
	

};

CanvasObject.prototype.setCss = function(name, value) {
	this.dprint("setCss: " + name + "->" + value);
	
	this.domElem.css(name, value);
	
	/*
	if (value == "") {
		delete this.customCss[name]
		this.domElem.css(name, "");
		
	} else {
		this.customCss[name] = value;
		this.domElem.css(name, value);
		
	}
	*/
	
	//theControlPanel().fullRefresh();
	//theControlPanel().objectAttributeChanged(name, value);
	//this.valueChanged();
};

CanvasObject.prototype.dumpHtml = function() {
	this.dprint("dumpHtml");
	
	//var str = "<"+this.tagType+" id=\"" + this.parent.id + "_" + this.id + "\" class=\"" + this.parent.id + '_object\" />';
	var str = this.recDumpHtml("");

	this.dprint(escapeHtml(str));
	
	return str;
};

CanvasObject.prototype.recDumpHtml = function(prefix) {

	this.dprint("recDumpHtml: " + this.id);

	var str = prefix + "<"+this.tagType+
	(this.tagProperties != "" ? " " + this.tagProperties : "") + 
	" id=\"" + this.id + "\" class=\"";
	for (var i in this.classes) {
		str += this.classes[i] + " ";
	}
	str += "\"";
	
	var numChildren = 0;
	for (var child in this.children) {
		numChildren++;
	}
	
	if (numChildren > 0 || this.content != "") {
		str += ">\n";
	} else {
		str += " >";
	}
	
	if (this.content != "") {
		str += prefix + '\t' + '<div class="content">' + this.content + '</div>\n';
	}
	
	var firstChild = true;
	for (var i in this.children) {
		if (firstChild) {
			//str += "\n";
			firstChild = false;
		}
		str += this.children[i].recDumpHtml("\t"+prefix) + "\n";
	}
	
	if (numChildren > 0 || this.content != "") {
		str += prefix + "</" + this.tagType + ">";
		//str += (firstChild ? "" : prefix) + "</" + this.tagType + ">";
	} else if (this.tagType == "textarea" || this.tagType == "div") {
		str += "</" + this.tagType + ">";
	}
	
	
	
	return str;
};

CanvasObject.prototype.dumpCss = function() {
	this.dprint("dumpCss");
	
	//var str = "<style>\n";
	
	return this.recDumpCss("\t");
	
	/*
	var str = "#"+ this.id +"{\n";
	
	for (var i=0; i<CanvasObject.attributes.length; i++) {
		var opt = CanvasObject.attributes[i];
		if (opt.cssName != undefined) {
			str += "\t\t" + opt.cssName + ": " + this[opt.name] + ";\n ";
		}
	}
	
	for (var attr in this.customCss) {
		var value = this.customCss[attr];
		str += "\t\t" + attr + ": " + value + ";\n ";
	} 
	
	str += "\t\tposition: absolute;\n";
	
	str += "\t}";
	*/
	
	return str;
};

CanvasObject.prototype.recDumpCss = function(prefix) {
	var str = prefix + "#"+ this.id +"{\n";
	
	for (var name in this.attributes) {
	
		var opt = this.attributes[name];
		
		if (opt.cssName != undefined && opt.value != "" && opt.cssName != "id") {
			str += prefix + "\t" + opt.cssName + ": " + opt.value + ";\n ";
		} 
	
	}
	
	/*
	for (var i=0; i<CanvasObject.attributes.length; i++) {
		var opt = CanvasObject.attributes[i];
		if (opt.cssName != undefined) {
			str += prefix + "\t" + opt.cssName + ": " + this[opt.name] + ";\n ";
		}
	}
	
	for (var attr in this.customCss) {
		var value = this.customCss[attr];
		if (value != "") {
			str += prefix + "\t" + attr + ": " + value + ";\n";
		}
	} 
	*/
	
	if (this.parent != null) {
		str += prefix + "\t" + "position: absolute;\n";
	} else {
		str += prefix + "\t" + "position: relative;\n";
		str += prefix + "\t" + "margin: auto;\n";
		str += prefix + "\t" + "display: block;\n";
		
	}
	
	str += prefix + "}\n";
	
	for (var i in this.children) {
		str += this.children[i].recDumpCss(prefix) + "\n";
	}
	
	return str;
}

CanvasObject.prototype.destroy = function() {
	this.dprint("destroy");
	
	this.domElem.remove();
};

CanvasObject.prototype.setIsSelected = function(value) {
	this.dprint("setIsSelected: " + value);

	this.isSelected = value;
	
	this.domElem.toggleClass("selected", value);

	// put selected element on top, so we can drag it even if
	// it is completely covered
	if (value) {
		this.domElem.css("z-index", "");
	} else {
		this.domElem.css("z-index", this.attributes['z-index'].value);
	}
	
	this.valueChanged();
};

CanvasObject.prototype.getSelectedObject = function() {
	return this.selectedObject;
};

CanvasObject.prototype.setSelectedObject = function(o) {
	
	this.dprint("setSelectedObject: " + o);
	
	if (this.selectedObject != null) {
		this.dprint("selectedObject was null before");	
		this.selectedObject.setIsSelected(false);
		this.selectedObject = null;
	}
	
	if (o == null) {
		this.dprint("set selected to null");
	} else {
	
		var obj = this.children[o.id];
		if (obj == this.selectedObject) {
			//this.dprint("object already selected");
			//return;
		}
		
		//this.dprint("setSelectedObject: " + obj);
		this.selectedObject = obj;
		obj.setIsSelected(true);
	
	}
	
	this.selectedChanged();
};

CanvasObject.prototype.setIsVisible = function(isVisible) {

	this.isVisible = isVisible;
	
	this.domElem.toggle(isVisible);
	//this.domElem.toggleClass("invisible", !isVisible);
	
	if(isVisible) {
		this.enableClickHandlers();
	} else {
		this.disableClickHandlers();
	}
	
	theControlPanel().fullRefresh();

};

//
//  CanvasObject Attribute Getters/Setters
//
CanvasObject.prototype.addClass = function(className) {
	this.dprint("addClass: " + className);
	
	var tokens = className.split(" ");
	for (var i=0; i<tokens.length; i++) {
		if(this.classes[tokens[i]] == undefined) {
			this.classes[tokens[i]] = tokens[i];
		}
	}
	theControlPanel().fullRefresh();
}

CanvasObject.prototype.removeClass = function(className) {
	this.dprint("removeClass: " + className);

	var tokens = className.split(" ");
	for (var i=0; i<tokens.length; i++) {
		if (this.classes[tokens[i]] != undefined) {
			delete this.classes[tokens[i]];
		}
	}
	theControlPanel().fullRefresh();
}

CanvasObject.prototype.setContent = function(newContent) {

	this.dprint("setContent: " + newContent);
	
	this.content = newContent;
	this.domElem.children(".content").remove();
	
	if (this.content != "") {
		this.domElem.append('<div class="content">'+this.content+'</div>');
	}
	
	this.valueChanged();
};

CanvasObject.prototype.setId = function(newId) {
	this.dprint("setId: " + newId);
	
	//var full_id = this.id + "_" + this.idNum;
	
	if (this.parent != null) {
		delete this.parent.children[this.id];
		//delete this.parent.children[full_id];
	} else {

	}
	
	this.idName = newId;
	this.id = this.idName + this.idNum;
	//full_id = this.id + "_" + this.idNum;
	
	this.domElem.attr('id', this.id);
	
	if (this.parent != null) {
		this.parent.children[this.id] = this;
	}
	
	this.valueChanged();
};

CanvasObject.prototype.setX = function(newX) {
	this.dprint("setX: " + newX);
	
	this.x = Math.floor(newX);
	this.domElem.css( "left", ""+(this.x)+"px" );
	
	//this.attributeChanged("x", newX);
	//this.valueChanged();
};

CanvasObject.prototype.setY = function(newY) {
	this.dprint("setY: " + newY);
	
	this.y = Math.floor(newY);
	this.domElem.css( "top", ""+(this.y)+"px" );
	
	//this.valueChanged();
	//this.attributeChanged("y", newY);
};

CanvasObject.prototype.setWidth = function(newW) {
	this.dprint("setWidth: " + newW);
	
	this.width = newW;
	
	this.domElem.css("width", ""+(newW)+"px");
	//this.valueChanged();
	//this.attributeChanged("width", newW);
};

CanvasObject.prototype.setHeight = function(newH) {
	this.dprint("setHeight: " + newH);
	this.height = newH;
	this.domElem.css("height", ""+(newH)+"px");
	//this.valueChanged();
	//this.attributeChanged("height", newH);
};

CanvasObject.prototype.setOpacity = function(op) {
	this.opacity = op;
	this.domElem.css("opacity", op);
};

CanvasObject.prototype.setBackground = function(bg) {
	this.background = bg;
	this.domElem.css("background", bg);
};

CanvasObject.prototype.setBackgroundImage = function(imgUrl) {
	this.dprint("set background image: " + imgUrl);
	
	
	
	if (imgUrl == "") {
		this.backgroundImage = "";
		this.domElem.css("background-image", "none");
	} else {
	
		var justUrl = "";
		var cssValue = "";
		if (imgUrl.indexOf("url('") == 0) {
			justUrl = imgUrl.substring(5, imgUrl.length - 2);
			cssValue = imgUrl;		
		} else {
			justUrl = imgUrl;
			cssValue = "url('"+imgUrl+"')";
		}
		
		if (imgUrl != cssValue) {
			this.setAttribute("background", "transparent");
		}
		
		var attr = this.attributes["backgroundImage"];
		attr.value = cssValue;
		this.backgroundImage = cssValue;
		this.domElem.css("background-image", cssValue);

		// Only dynamically resize the canvas if they provide just
		// an image url.  That way, saved, css values for save/load
		// will not resize the canvas, since we know the width height
		// that the user specified
		if (imgUrl != cssValue) {
		
			
		
			var _parent = this;
			var _img = new Image();
			_img.src=justUrl;
			
			_img.onload = function() {
				cprint("image loaded");
				cprint("w: "+_img.width);
				cprint("h: "+_img.height);
				
				_parent.setAttribute("width", _img.width);
				_parent.setAttribute("height", _img.height);
			}
			_img.onerror=function() {
				cprint("image error");
				_parent.setBackgroundImage("");
			};
			_img.onabort=function() {
				cprint("image abort");
				_parent.setBackgroundImage("");
			};
		
		}
	}
	this.valueChanged();
};

//
// Notifier methods
//

CanvasObject.prototype.attributeChanged = function(name, value) {
	//theControlPanel().objectAttributeChanged(name, value);
};

CanvasObject.prototype.valueChanged = function() {
	theControlPanel().fullRefresh();
};

CanvasObject.prototype.selectedChanged = function() {
	theControlPanel().fullRefresh();
};

//
// Debug Methods
// 

CanvasObject.prototype.dprint = function(str) {
	if (CanvasObject.debug) {
		cprint(CanvasObject.className + " " + this.id + ": " + str, "#ff0000");
	}
}